/**
 * @describe 材质模块方法
 * @function getModelMaterialList 获取当前模型材质
 * @function setModelPositionSize 设置模型定位缩放大小
 * @function getModelMaps 获取模型自带贴图
 * @function onSetModelMaterial 设置材质属性（网格,透明度，颜色，深度写入）
 * @function onSetModelMap 设置模型贴图（模型自带）
 * @function onSetSystemModelMap 设置模型贴图（系统贴图）
 * @function onChangeModelMaterial 选择材质
 * @function onGetEditMeshList 获取最新材质信息列表
 * @function onChangeModelMeshType 切换材质类型
 * @function onSetGeometryMeshList 设置几何体模型材质
 * @function initModelMaterial 重置模型材质数据
 * @function onSetMeshVisible 设置材质显隐
 */
import * as THREE from 'three'
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'
import { useMeshEditStore } from '@/store/meshEditStore'
import TWEEN from "@tweenjs/tween.js";
const store = useMeshEditStore()
let targetPosition = { x: 0, y: 0, z: 0 }
// 获取当前模型材质
function getModelMaterialList() {
  this.modelMaterialList = []
  let i = 0;
  this.model.traverse((v) => {
    if (v.isMesh && v.material) {
      v.castShadow = true
      v.frustumCulled = false
      if (Array.isArray(v.material)) {
        v.material = v.material[0]
        this.setMaterialMeshParams(v, i)
      } else {
        this.setMaterialMeshParams(v, i)
      }
    }
    // else if(v.isMesh){
    //   const worldPosition = new THREE.Vector3();  // 创建一个 Vector3 用于保存位置
    //   console.log('v======v', v.getWorldPosition(worldPosition));
    // }
  })
}
// 材质参数二次处理
function setMaterialMeshParams(v, i) {
  const newMesh = v.clone()
  Object.assign(v.userData, {
    rotation: newMesh.rotation,
    scale: newMesh.scale,
    position: newMesh.position,
  })
  const newMaterial = v.material.clone()
  v.mapId = v.name + '_' + i
  v.material = newMaterial
  const { mapId, uuid, userData, type, name, isMesh, visible } = v
  const { color, wireframe, depthWrite, opacity } = v.material
  const meshMaterial = { color, wireframe, depthWrite, opacity }
  const mesh = {
    mapId, uuid, userData, type, name, isMesh, visible, material: meshMaterial
  }
  this.modelMaterialList.push(mesh)
  const cloneMesh = v.material.clone()
  cloneMesh.userData.mapId = v.name + '_' + i
  this.originalMaterials.set(v.uuid, cloneMesh);
}
// 设置模型定位缩放大小
function setModelPositionSize() {
  //设置模型位置
  this.model.updateMatrixWorld()
  const box = new THREE.Box3().setFromObject(this.model);
  const size = box.getSize(new THREE.Vector3());
  const center = box.getCenter(new THREE.Vector3());
  // 计算缩放比例
  const maxSize = Math.max(size.x, size.y, size.z);
  const targetSize = 2.5; // 目标大小
  const scale = targetSize / (maxSize > 1 ? maxSize : .5);
  this.model.scale.set(scale, scale, scale)
  // 设置模型位置
  this.model.position.sub(center.multiplyScalar(scale))
  // 设置控制器最小缩放值
  this.controls.maxDistance = size.length() * 10
  // 设置相机位置
  this.camera.position.set(0, 2, 6)
  // 设置相机坐标系
  this.camera.updateProjectionMatrix();
}
// 获取模型自带贴图
function getModelMaps(materials) {
  let textureMap = {}
  materials.forEach(texture => {
    if (texture.map && texture.map.image) {
      const canvas = document.createElement('canvas')
      canvas.width = 75
      canvas.height = 75
      const context = canvas.getContext('2d')
      context.drawImage(texture.map.image, 0, 0)
      textureMap = {
        url: canvas.toDataURL('image/png', .5),
      }
      canvas.remove()
    }
  })
  return textureMap
}
// 设置材质属性
function onSetModelMaterial(config) {
  const { color, wireframe, depthWrite, opacity } = JSON.parse(JSON.stringify(config))
  const uuid = store.selectMesh.uuid
  const mesh = this.scene.getObjectByProperty('uuid', uuid)
  if (mesh && mesh.material) {
    const { name, map } = mesh.material
    Object.assign(mesh.material, {
      map,
      name,
      transparent: true,
      color: new THREE.Color(color),
      wireframe,
      depthWrite,
      opacity
    })
  }
  // 修改当前材质列表的参数
  const listMesh = this.modelMaterialList.find((v) => v.uuid == uuid) || {};
  Object.assign(listMesh.material, {
    color: new THREE.Color(color),
    wireframe,
    depthWrite,
    opacity
  })
}
// 修改材质显隐
function onSetMeshVisible(config) {
  const mesh = this.scene.getObjectByProperty('uuid', config.uuid)
  mesh.visible = config.visible
}
//删除模型
function deleteZJ() {
  // onSetMeshVisible(this.currentModelItem);
  console.log('this.currentModelItem', this.currentModelItem);
  this.currentModelItem.visible = !this.currentModelItem.visible;
}

// 设置模型贴图（模型自带）
function onSetModelMap({ mapId, meshName }) {
  const uuid = store.selectMesh.uuid
  const mesh = this.scene.getObjectByProperty('uuid', uuid)
  const originMaterial = this.originalMaterials.get(uuid)
  mesh.material = originMaterial.clone()
  mesh.mapId = mapId
  // 设置当前材质来源唯一标记值key 用于预览处数据回填需要
  mesh.meshFrom = meshName
}

// 设置模型贴图（系统贴图）
function onSetSystemModelMap({ id, url }) {
  return new Promise((resolve) => {
    const uuid = store.selectMesh.uuid
    const mesh = this.scene.getObjectByProperty('uuid', uuid)
    const texture = new THREE.TextureLoader().load(url)
    const newMaterial = mesh.material.clone()
    newMaterial.map = texture
    newMaterial.map.wrapS = THREE.MirroredRepeatWrapping;
    newMaterial.map.wrapT = THREE.MirroredRepeatWrapping;
    newMaterial.map.flipY = false
    newMaterial.map.colorSpace = THREE.SRGBColorSpace
    newMaterial.map.minFilter = THREE.LinearFilter;
    newMaterial.map.magFilter = THREE.LinearFilter;
    mesh.material = newMaterial
    mesh.mapId = id
    // 设置当前材质来源唯一标记值key 用于预览处数据回填需要
    mesh.meshFrom = id
    texture.dispose()
    resolve()
  })
}
// 设置模型贴图 (外部)
function onSetStorageModelMap(url, type) {
  return new Promise(async (resolve) => {
    const uuid = store.selectMesh.uuid
    const mesh = this.scene.getObjectByProperty('uuid', uuid)
    // 根据 图片类型选择不同的加载器
    let loader
    let texture
    if (type == 'hdr') {
      loader = new RGBELoader()
    } else {
      loader = new THREE.TextureLoader()
    }
    texture = await loader.loadAsync(url)
    const newMaterial = mesh.material.clone()
    newMaterial.map = texture
    newMaterial.map.wrapS = THREE.MirroredRepeatWrapping;
    newMaterial.map.wrapT = THREE.MirroredRepeatWrapping;
    newMaterial.map.flipY = false
    newMaterial.map.colorSpace = THREE.SRGBColorSpace
    newMaterial.map.minFilter = THREE.LinearFilter;
    newMaterial.map.magFilter = THREE.LinearFilter;
    mesh.material = newMaterial
    texture.dispose()
    resolve()
  })
}
// 选择材质
function onChangeModelMaterial(name) {
  const mesh = this.model.getObjectByName(name)
  this.outlinePass.selectedObjects = [mesh]
  store.selectMeshAction(mesh)
  return mesh
}
// 拖拽事件
function handleMouseMove(event) {
  // 如果发生了拖拽，清除计时器
  if (this.dragTimer) {
    clearTimeout(this.dragTimer);
    this.dragTimer = null;
  }
}
// 模型悬浮事件
function onMouseHoverModel(event) {



}

function setExpertHover(child) {
  child.addEventListener('mouseover', function () {
    console.log('123', child.name);
  });
}

// 射线投射器
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();

// 模型点击事件
function onMouseClickModel(event) {
  const { clientHeight, clientWidth, offsetLeft, offsetTop } = this.container
  this.mouse.x = ((event.clientX - offsetLeft) / clientWidth) * 2 - 1
  this.mouse.y = -((event.clientY - offsetTop) / clientHeight) * 2 + 1
  this.raycaster.setFromCamera(this.mouse, this.camera)
  let model
  if (this.model) model = this.model
  if (this.geometryGroup.children.length) model = this.geometryGroup
  if (!model) return false
  const intersectsChildren = this.raycaster.intersectObjects(model.children, true)
  const intersects = intersectsChildren.filter(item => item.object.isMesh && item.object.material)
  if (intersects.length > 0) {
    const intersectedObject = intersects[0].object
    console.log(intersectedObject);
    // 保存当前专家
    this.currentModelItem = intersectedObject;
    const name = 'ZhuanJia'
    if (intersectedObject.name.startsWith(name)) {
      handlePosition(intersectedObject, this)
    }
    // this.outlinePass.visibleEdgeColor = new THREE.Color('#FF8C00') // 可见边缘的颜色
    // this.outlinePass.hiddenEdgeColor = new THREE.Color('#8a90f3') // 不可见边缘的颜色
    // this.outlinePass.selectedObjects = [intersectedObject]
    // store.selectMeshAction(intersectedObject)
    if (this.transformControls) {
      const boundingBox = new THREE.Box3().setFromObject(intersectedObject);
      const { dragPosition } = intersectedObject.userData
      //检测当前模型位置是否有初始值
      if (dragPosition) {
        this.transformControls.position.copy(dragPosition);
      } else {
        const center = boundingBox.getCenter(new THREE.Vector3());
        intersectedObject.userData.dragPosition = center
        this.transformControls.position.copy(center);
      }
      this.transformControls.attach(intersectedObject)
    }
  } else {
    if (!this.transformControls) {
      this.outlinePass.selectedObjects = []
      store.selectMeshAction({})
    }
  }
  // }, 200); // 设置一个阈值，例如200毫秒
}
function handlePosition(obj, that) {
  let box3 = new THREE.Box3()
  box3.expandByObject(obj) // 计算模型包围盒
  let size = new THREE.Vector3()
  box3.getSize(size) // 计算包围盒尺寸
  let center = new THREE.Vector3()
  box3.getCenter(center) // 计算一个层级模型对应包围盒的几何体中心坐标
  function maxSize(vec3) {
    let max
    if (vec3.x > vec3.y) {
      max = vec3.x
    } else {
      max = vec3.y
    }
    if (max > vec3.z) {
    } else {
      max = vec3.z
    }
    return max
  }
  let max = maxSize(size) //包围盒长宽高中最大的一个值，用来表征模型的尺寸
  // 1.控制渲染范围，但是不要忘记相机位于模型包围盒之外
  let position = center.clone().addScalar(max);//相机位置
  console.log("x<0.1", position);
  // 纠正相机位置
  // 左侧专家视角
  if (position.x < 0.32 && position.z > 0.62) {
    console.log("x<0.2");
    that.controls.maxAzimuthAngle = Infinity //水平旋转的角度上限
    that.controls.minAzimuthAngle = -Infinity //水平旋转的角度下限
    that.controls.maxPolarAngle = 1.6 //垂直旋转的角度的上限
    that.controls.minPolarAngle = 0.867 //垂直旋转的角度的下限
    position.z = position.z - 0.081;
    position.x = position.x - 0.42;
    position.y = position.y - 0.11;
    // 中心专家视角
  } else if (position.z < 1.37 && position.x < 0.54 && position.x > 0.53 && position.y < 0.54) {
    console.log("x<0.3");
    that.controls.maxAzimuthAngle = Infinity //水平旋转的角度上限
    that.controls.minAzimuthAngle = -Infinity //水平旋转的角度下限
    that.controls.maxPolarAngle = 1.6 //垂直旋转的角度的上限
    that.controls.minPolarAngle = 0.867 //垂直旋转的角度的下限
    position.z = position.z - 0.08;
    position.x = position.x - 0.48;
    position.y = position.y - 0.121;
    // 右后侧专家视角
  } else if (position.z < 0.36 && position.x > 0.95) {
    console.log("x<0.4");
    that.controls.maxAzimuthAngle = 0.8 //水平旋转的角度上限
    that.controls.minAzimuthAngle = -1.8 //水平旋转的角度下限
    that.controls.maxPolarAngle = 1.6 //垂直旋转的角度的上限
    that.controls.minPolarAngle = 0.867 //垂直旋转的角度的下限
    position.z = position.z - 0.1;
    position.x = position.x - 0.1;
    position.y = position.y - 0.1;
    // 左后侧专家视角
  } else if (position.z < 0.33 && position.x > -0.03 && position.y < 0.51) {
    console.log("x<0.5");
    that.controls.maxAzimuthAngle = 1.8 //水平旋转的角度上限
    that.controls.minAzimuthAngle = -0.55 //水平旋转的角度下限
    that.controls.maxPolarAngle = 1.6 //垂直旋转的角度的上限
    that.controls.minPolarAngle = 0.867
    // position.z = position.z - 0.13;
    position.x = position.x - 0.40;
    position.y = position.y - 0.131;
  }
  moveCamera(position, that)
  // that.camera.position.copy(position);
  // 2. 居中渲染：设置相机目标观察点，指向包围盒几何中心
  // that.camera.lookAt(center)
  // 3.注意near和far尺寸控制
  that.camera.near = max * 0.1//最好和相机位置或者说包围盒关联，别设置0.1 1之类看似小的值
  that.camera.far = max * 300//根据相机位置和包围大小设置，把包围盒包含进去即可，宁可把偏大，不可偏小
  that.camera.updateProjectionMatrix()//渲染范围改变，注意更新投影矩阵
  that.controls.target.copy(center)
  that.controls.update()
}
function moveCamera(pos, that) {
  let areEqual = targetPosition.x !== pos.x || targetPosition.y !== pos.y || targetPosition.z !== pos.z;
  if (areEqual) {
    targetPosition = pos
    new TWEEN.Tween(that.camera.position)
      .to(pos, 2000) // 动画持续时间2秒
      .start();
  }
}
// 获取最新材质信息列表
function onGetEditMeshList() {
  const meshList = []
  this.model.traverse((v) => {
    if (v.isMesh && v.material) {
      const { color, opacity, depthWrite, wireframe } = v.material
      const obj = {
        meshName: v.name,
        meshFrom: v.meshFrom,
        color: color.getStyle(),
        opacity, depthWrite, wireframe,
        visible: v.visible,
        type: v.material.type
      }
      meshList.push(obj)
    }
  })
  return meshList
}
// 设置材质类型
function onChangeModelMeshType(activeMesh) {
  this.model.traverse(v => {
    if (v.isMesh && v.material) {
      const { name, color, map, wireframe, depthWrite, opacity } = v.material
      if (activeMesh.type) {
        v.material = new THREE[activeMesh.type]({
          map,
          transparent: true,
          color,
          name,
        })
      } else {
        const originalMaterial = this.originalMaterials.get(v.uuid);
        v.material = originalMaterial;
      }
      depthWrite ? v.material.depthWrite = depthWrite : ''
      opacity ? v.material.opacity = opacity : ''
      wireframe ? v.material.wireframe = wireframe : ''
      v.material.side = THREE.DoubleSide
    }
  })
}
// 设置几何体材质
function onSetGeometryMeshList(v) {
  this.modelMaterialList = []
  this.model.traverse((v) => {
    const { name } = v
    v.castShadow = true
    v.frustumCulled = false
    if (v.isMesh && v.material) {
      this.modelMaterialList.push(v)
      this.originalMaterials.set(v.uuid, v.material)
      v.mapId = name
    }
  })
}
// 重置模型材质数据
function initModelMaterial() {
  this.model.traverse(v => {
    if (v.isMesh && v.material) {
      // 获取原始材质类型
      const originalMaterial = this.originalMaterials.get(v.uuid);
      v.material = originalMaterial.clone();
      v.mapId = originalMaterial.userData.mapId
      v.visible = true
      v.meshFrom = null
    }
  });
  this.modelMaterialList.forEach((v) => {
    v.visible = true
    const originalMaterial = this.originalMaterials.get(v.uuid);
    v.mapId = originalMaterial.userData.mapId
    const { color, wireframe, depthWrite, opacity } = originalMaterial
    Object.assign(v.material, {
      color, wireframe, depthWrite, opacity
    })
  })
  store.selectMeshAction({})
}
export default {
  getModelMaterialList,
  setModelPositionSize,
  getModelMaps,
  onSetModelMaterial,
  onSetModelMap,
  onSetSystemModelMap,
  onSetStorageModelMap,
  onChangeModelMaterial,
  onMouseClickModel,
  setExpertHover,
  onMouseHoverModel,
  onGetEditMeshList,
  onChangeModelMeshType,
  onSetGeometryMeshList,
  onSetMeshVisible,
  initModelMaterial,
  setMaterialMeshParams,
  handlePosition,
  deleteZJ
}
